
// AnimationManager.cpp : implementation of the AnimationManager class
//
#include "stdafx.h"
#include "WorldBuilder.h"
#include "AnimationManager.h"
#include "NodeManager.h"
#include "ActionManager.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif



AnimationManager & AnimationManager::instance()
{
    static AnimationManager theInstance;
    return theInstance;
}

AnimationManager::AnimationManager()
{
}

//
//bool blocksTooSimilar(const Node & a, const Node & b) 
//{
//    
//    ref<Shape> result;
//
//    gx::Quat aQuat = a.getGlobalTransform().rotation;
//    gx::Quat bQuat = b.getGlobalTransform().rotation;
//    if(aQuat.dist(bQuat) > .1)
//    {
//        return false;
//    }
//
//    // TODO use dist2
//    if(a.getScale().dist(b.getScale()) > 1e-1)
//    {
//        return false;
//    }
//    
//    // TODO use dist2
//    if(a.getGlobalTransform().translation.dist(b.getGlobalTransform().translation) > 1e-1)
//    {
//        return false;
//    }
//
//    return true;
//}
//
//void AnimationManager::startBlockAnimation(const Node & block, 
//	ref<const Shape> iniShape, ref<Shape> finalShape, double totalTime, ref<Action> action) 
//{
//	// If "iniShape" is NULL, we use the current shape at the specified  block 
//	if(iniShape == NULL)
//	{
//		iniShape = block.getShape()->clone();
//	}
//
//	// If the difference is too small we don't bother to start an animation,
//	// instead we simply perform the action and finish. This is important for
//	// actions that can be triggered from spinner UI controls (e.g., scaling)
//	if(shapesTooSimilar(iniShape.get(), finalShape.get()))
//	{
//		ActionManager::instance().performAction(action);
//	}
//	// If the difference is big enought we initialize an ActionInfo object with 
//	// the necessary info and that info to the map, where it will be later
//	// retreived whern performAnimationStep() is called
//	else
//	{
//		AnimationInfo info;
//		info.initialShape = iniShape; 
//		info.intermediateShape =  info.initialShape->clone();
//		info.finalShape = finalShape;
//		info.action = action;
//		info.elapsedTime = 0.;
//		info.totalTime = totalTime;
//
//		// TODO what if there was already one?
//		m_animatedBlocks.insert(std::make_pair(block, info));
//	}
//}

bool AnimationManager::isBlockAnimated(ref<Node> block) const 
{
    return m_animatedBlocks.find(block) != m_animatedBlocks.end();
}

const AnimationInfo & AnimationManager::getAnimationInfo(
    ref<Node> block) const
{
    ASSERT(isBlockAnimated(block));
    return m_animatedBlocks.find(block)->second;
}

void AnimationManager::updateIntermediateShape(
    ref<Node> block, const gx::Mat4& newIntermShape, double deltaTime)
{
    ASSERT(isBlockAnimated(block));
    m_animatedBlocks[block].elapsedTime += deltaTime;
    m_animatedBlocks[block].intermediateShape = newIntermShape;
}

AnimationManager::BlockInfoMap::const_iterator 
    AnimationManager::finalizeAnimation(ref<Node> block)
{
 /*   ASSERT(isBlockAnimated(block));
    AnimationManager::BlockInfoMap::iterator it = m_animatedBlocks.find(block);
    if(it->second.action != NULL)
    {
        ActionManager::instance().performAction(it->second.action);
    }
    return m_animatedBlocks.erase(it);*/
    return AnimationManager::BlockInfoMap::const_iterator ();
}

// deltaT is milliseconds
//ref<Shape> interpShapes(const Shape * curr, const Shape * final, double u) 
//{
//	ASSERT(u >= 0. && u <= 1.);
//
//	ref<Shape> result;
//
//	// Interpolate orientation
//	gx::Quat interpOrient = gx::Quat::slerp(
//		curr->getOrientation(), final->getOrientation(), u);
//	
//	// TODO refactor these into interp(a, b, u) func
//
//	// Interpolate scale
//	gx::Vec3 interpScale = curr->getScale() * (1 - u) + final->getScale() * u;
//
//	// Interpolate position
//	gx::Vec3 interpPos = curr->getPosition() * (1 - u) + final->getPosition() * u;
//	
//	result = curr->clone();
//	result->setOrientation(interpOrient);
//	result->setPosition(interpPos);
//	result->setScale(interpScale);
//
//	return result;
//}

//bool AnimationManager::performAnimationStep(double elapsedMillis)
//{
//	bool updatedSomething = false;
//
//	typedef AnimationManager::BlockInfoMap::const_iterator It;
//	It it = AnimationManager::instance().getBlockInfoMap().begin();
//	for(; it != AnimationManager::instance().getBlockInfoMap().end(); )
//	{
//		const Node & block = it->first;
//		const AnimationInfo & info = it->second;
//
//		double deltaT = elapsedMillis;
//
//		bool finished = false;
//
//		ASSERT(info.elapsedTime < info.totalTime);
//
//		if(info.elapsedTime + deltaT > info.totalTime)
//		{
//			deltaT = info.totalTime - info.elapsedTime;
//			finished = true;
//		}
//		
//		updatedSomething = true;
//		AnimationManager::instance().updateIntermediateShape(
//			block, 
//			interpShapes(info.initialShape.get(), 
//				info.finalShape.get(), info.elapsedTime / info.totalTime),
//			deltaT);
//		
//		if(finished)
//		{
//			it = AnimationManager::instance().finalizeAnimation(block);
//		}
//		else
//		{
//			++it;
//		}
//	}
//
//	return updatedSomething;
//}

void AnimationManager::performAnimatedInsertBlockAction(
    ref<Node> block)
{
    //ActionManager::instance().performAction(ref<Action>(
    //	new InsertBlockAction(block, shape)));

    //ref<Shape> verySmall = shape->clone();
    //verySmall->setScale(gx::zero);
    //startBlockAnimation(block, verySmall, shape, 100., ref<Action>());
}

void AnimationManager::performAnimatedEraseBlockAction(const Node &)
{
    //ref<const Shape> currentShape = block.getShape();
    //ref<Shape> verySmall = currentShape->clone();
    //verySmall->setScale(gx::zero);

    //startBlockAnimation(block, currentShape, verySmall, 100., 
    //	ref<Action>(new EraseBlockAction(block)));
}